Immutability has been getting popular these last years, especially with the rise of not only functional programming and but also JS frameworks such as React.
It’s an important concept for many reasons, but I won’t get into it in this blog post because it’s not the point. Although I would urge you to either read The Dao of Immutability or watch Jon Skeet’s The changing state of immutability in c# video, which explain it in details.
The true constant is change. Mutation hides change. Hidden change manifests chaos. Therefore, the wise embrace history.
C# 9 is trying to embrace Immutability more, by introducing a new type, record
and init
-only properties. I finally had the time to play with them, and I’m very excited for when C# 9 will be officially out!
How to try C# 9 features
I’m sure some of you would like to try the new C# 9 features, here’s how/where I do it:
- LINQPad 6 Beta: by activating the experimental .NET 5 runtime.
- SharpLab: by choosing the master Roslyn branch.
Init-only Properties
Imagine you have the following class:
public class Rectangle
{
public double Width { get; set; }
public double Height { get; set; }
}
Now you can create instances of it:
var item1 = new Rectangle
{
Width = 10,
Height = 5
};
Which is fine, but we can change Width
and Height
whenever we want. What if we don’t want that? What if we want our Rectangle
to be immutable?
public class Rectangle
{
public double Width { get; }
public double Height { get; }
public Rectangle(double width, double height)
{
Width = width;
Height = height;
}
}
As you can see, we’ll need to make the properties read-only and add a constructor that fills them. This just adds boilerplate (a parameterized constructor) and removes the possibility to use object initializers.
The new init
keyword comes to the rescue:
This means that we can only change (set) the values of Width
and Height
when instantiating Rectangle
. After that, you can’t change the values of these properties, which essentially makes our class immutable!
Records
If you want to read the official proposal, which contains the full details, visit records.md.
Init-only properties are already doing a good job to promote immutability in C#, so you might be wondering why records are such an important addition to the language.
Records are here for two main reasons:
- A lot of our classes are “data-holders”, and creating them requires a lot of boilerplate.
- Immutability can be enhanced by things like value-based equality and deep cloning, which are automatically generated for you.
Deep dive
In order to make our Rectangle
a record, all we need is to change the class
keyword:
public record Rectangle
{
public double Width { get; init; }
public double Height { get; init; }
}
Which will be turned to this by the compiler:
Here are the key things that you need to know about:
- Line 11: A generated property used in the
Equals
method to only compare two instances of the same type, so inheritance won’t matter. - Line 49: A generated
Clone
method that uses the copy constructor to clone the instance. - Line 60: A generated override of
Object.Equals
. - Line 65: A generated virtual
Equals
method that does a full value-based comparison. - Line 70: A generated copy constructor that copies the values of all the fields.
- Line 80: A generated
IEquatable<Rectangle>.Equals
that uses the generatedEquals
method, since our generated class implementsIEquatable<Rectangle>
.
Ways to define records
There are a couple of ways to define records:
With-expressions
Since we’re working with immutable data, a core concept is to create new object from existing one, by changing one or more properties. C# 9 adds the with
expression, which is just a syntax sugar:
Here’s the actual generated code:
As you can see, the with
expressions turn into a Clone
+ manual set of the changed properties. Note that with
works with init
properties because it uses the object initializer syntax.
Conclusion
Init-only properties and Records will boost our productivity and help us embrace immutability into our software. Personally, I can’t wait to use this in Blazor to manage state.
C# 9 is without a doubt a great milestone for the language. I only presented two features, but the version comes with a lot more! Make sure to check them out here.
Hope you enjoyed the post, see you soon!